package com.example.test003.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.test003.domain.ResponseResult;
import com.example.test003.domain.entity.SysUser;
import com.example.test003.domain.vo.LoginVo;
import com.example.test003.domain.vo.UserInfoVo;
import com.example.test003.enums.AppHttpCodeEnum;
import com.example.test003.service.FaceService;
import com.example.test003.utils.BeanCopyUtils;
import com.example.test003.utils.JwtUtil;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@CrossOrigin
public class VoiceController {
    /**
     * 授权：需要在开放平台获取【https://ai.data-baker.com/】
     */
    private static final String clientId = "80074922285849f29756bd95a4a3d023";
    private static final String clientSecret = "a297a7e58fdb42f5948ada12f97bbbf1";


    /**
     * partition 声纹库分组标识id
     */
    private static final String partition = "";

    /**
     * 获取token的地址信息
     */
    public static String tokenUrl = "https://openapi.data-baker.com/oauth/2.0/token?grant_type=client_credentials&client_secret=%s&client_id=%s";

    /** 创建声纹ID API地址 */
    private static String createUrl = "https://openapi.data-baker.com/vpr/v2/createid";
    /** 声纹注册API地址 */
    private static String registUrl = "https://openapi.data-baker.com/vpr/v2/register";
    /** 查询声纹状态码API地址 */
    private static String queryStatusUrl = "https://openapi.data-baker.com/vpr/v2/status";
    /** 删除声纹API地址 */
    private static String deleteUrl = "https://openapi.data-baker.com/vpr/v2/delete";
    /** 声纹验证(1:1)API地址 */
    private static String matchUrl = "https://openapi.data-baker.com/vpr/v2/match";
    /** 声纹对比(1:N)API地址 */
    private static String searchUrl = "https://openapi.data-baker.com/vpr/v2/search";

    @Autowired
    private FaceService sysUserService;

    public ResponseResult login(SysUser sysUser){
        String jwt= JwtUtil.createJWT(sysUser.getId().toString());
        UserInfoVo userInfoVo = BeanCopyUtils.copyBean(sysUser, UserInfoVo.class);
        LoginVo loginVo = new LoginVo(jwt,userInfoVo);
        return ResponseResult.okResult(loginVo);
    }

    @PostMapping(value = "/voice", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ResponseResult uploadAudioData(@RequestPart("userName") String userName,
                                @RequestPart("audioFile") MultipartFile audioFile) throws Exception {
        //打他String其实就是用户名
        SysUser user = sysUserService.getFaceByUsername(userName);

        System.out.println(userName);
        System.out.println("接收到的音频文件名：" + audioFile.getOriginalFilename());
        System.out.println("接收到的音频文件大小：" + audioFile.getSize());
        // 保存音频文件到本地
        String filePath="";
        try {
            filePath = "C:\\Users\\Cold'Rain\\Desktop\\test003\\src\\main\\java\\com\\example\\test003\\pcm\\xjl.wav";
            File destFile = new File(filePath);
            audioFile.transferTo(destFile);
            System.out.println("音频文件保存成功：" + filePath);
        } catch (IOException e) {
            System.out.println("音频文件保存失败：" + e.getMessage());
        }

        try {
            // 创建ProcessBuilder对象，并指定要执行的命令
            ProcessBuilder processBuilder = new ProcessBuilder("C:\\Users\\Cold'Rain\\Downloads\\ffmpeg-2024-04-04-git-478d97f303-essentials_build\\bin\\ffmpeg", "-y", "-i", "C:\\Users\\Cold'Rain\\Desktop\\test003\\src\\main\\java\\com\\example\\test003\\pcm\\xjl.wav", "-acodec", "pcm_s16le", "-f", "s16le", "-ac", "2", "-ar", "16000", "C:\\Users\\Cold'Rain\\Desktop\\test003\\src\\main\\java\\com\\example\\test003\\pcm\\xjl.pcm");

            // 启动进程
            Process process = processBuilder.start();

            // 读取进程的输出流
            InputStream inputStream = process.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }

            // 等待进程执行完毕
            int exitCode = process.waitFor();
            System.out.println("Exit Code: " + exitCode);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        try {
            JSONObject result = doMatch(filePath,user.getVoice());
            System.out.println(result);
            try {
                double score = result.getDouble("score");

                if (score > 40) {
                    System.out.println("Score is greater than 40");
                    ResponseResult responseResult = login(user);
                    return responseResult;
                } else {
                    System.out.println("Score is not greater than 40");
                    return ResponseResult.errorResult(AppHttpCodeEnum.FACE_ERROR);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return ResponseResult.errorResult(AppHttpCodeEnum.FACE_ERROR);
    }

    public static JSONObject doMatch(String path,String voiceId) throws Exception {
        Map<String,Object> params = new HashMap<>();
        params.put("access_token",getAccessToken());
        params.put("format","pcm");
        params.put("audio",encodeBase64File(path)); //获取音频数据地址
        params.put("scoreThreshold",30.0);             //分数阈值
        params.put("matchId",voiceId);         //声纹库id
        params.put("partition", partition);                    //所使用registerId使用了partition参数时，为必填，否则会报错
        String rightResultdesc = "声纹1:1验证完成，结果信息";
        String wrongResultdesc = "声纹1:1验证失败，结果信息";
        JSONObject jsonObject = sendReqUtil(params, matchUrl, rightResultdesc, wrongResultdesc);
        return jsonObject;
    }

    public static String encodeBase64File(String path) throws Exception {
        File file = new File(path);
        FileInputStream inputFile = new FileInputStream(file);
        byte[] buffer = new byte[(int) file.length()];
        inputFile.read(buffer);
        inputFile.close();
        return Base64.getEncoder().encodeToString(buffer);
    }

    private static JSONObject sendReqUtil(Map<String,Object> params,String url,String rightResultdesc,String wrongResultdesc){
        try {
            OkHttpClient client = new OkHttpClient().newBuilder()
                    .connectTimeout(60, TimeUnit.SECONDS)
                    .readTimeout(60, TimeUnit.SECONDS)
                    .writeTimeout(60, TimeUnit.SECONDS)
                    .build();
            okhttp3.MediaType mediaType = okhttp3.MediaType.parse("application/json");
            RequestBody body = RequestBody.create(mediaType, JSONObject.toJSONString(params));
            //构造request
            Request request = new Request.Builder()
                    .url(url)
                    .method("POST", body)
                    .addHeader("Content-Type", "application/json")
                    .build();
            Response response = null;
            response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                JSONObject jsonObject = JSON.parseObject(response.body().string());
                System.out.println(rightResultdesc + ": " + (jsonObject == null ? "" : jsonObject));
                return jsonObject;
            } else {
                System.out.println(wrongResultdesc + ": " + response.body().string());
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getAccessToken() {
        String accessToken = "";
        OkHttpClient client = new OkHttpClient();
        String url = String.format(tokenUrl, clientSecret, clientId);
        Request request = new Request.Builder().url(url).build();
        JSONObject jsonObject;
        try {
            Response response = client.newCall(request).execute();
            if (response.isSuccessful()) {
                //解析
                String resultJson = response.body().string();
                jsonObject = JSON.parseObject(resultJson);
                accessToken = jsonObject.getString("access_token");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return accessToken;
    }
}
